using System;
using System.Reflection;
using System.Text;
using System.Collections.Generic;
using Sce.PlayStation.Core;
using Sce.PlayStation.Core.Imaging;
using Sce.PlayStation.Core.Environment;
using Sce.PlayStation.HighLevel.UI;
using VitaReader;

namespace VitaReaderLibPS
{
    internal class Reading : ReaderUI , IReadingHandler
    {
		//Panel		UIPnReadingRoot;
			ScrollPanel UISpTextContent;
		
		internal Label[] mPages;
		internal int[] mPageIndex;
		internal PagePos[] mPageInfo;
		
		const int PAGE_COUNT = 3;
		const float MAX_VIEW_HEIGHT = 2048;
		const int MIN_FONT_SIZE = 20;
		const int MAX_FONT_SIZE = 60;
		
		#region IReadingHandler interface
		//open file
		void IReadingHandler.ReadingOpen(String file)
		{
			(this as IReadingHandler).ReadingClose();
			BookInfo book = mScene.CurrentBook;
			if( mScene.Data.OpenFile(file,out book) )
			{
				for(int i = 0; i < PAGE_COUNT; ++i)
				{
					if( i == 0 )
						mPageInfo[0].Start = book.LastPos;
					else
						mPageInfo[i].Start = mPageInfo[i-1].Start + mPageInfo[i-1].Size;
					
					//String text = "";
					ReadResult result = mScene.Data.ReadForwardFile(ref mPageInfo[i], ref mPages[i] );
					if( result != ReadResult.ERROR )
					{
						//mPages[i].Text = text;
						//mPages[i].Height = mScene.View.Height;
						if(result == ReadResult.OK )
							mPages[i].Height = (mPageInfo[i].LinePos.Count+0.2f)*mScene.View.GetFontHeight();
						//mPages[i].Height = Math.Min(MAX_VIEW_HEIGHT, mPages[i].TextHeight );						
					}
				}//for
				
				mScene.CurrentBook = book;
				UpdateReadPageLayout();
				UISpTextContent.PanelY = 0;
				mScene.ShowUI(UIType.READING);
			}
			else
			{
				String info = String.Format( mScene.Language.MsgFileNotFound, file);
				mScene.ShowMessageBox( mScene.Language.TitleError, info);
				book.FileName = null;
				mScene.CurrentBook = book;
			}
			mReadingHelp = false;
		}
		//close file
		void IReadingHandler.ReadingClose()
		{
			int linePos = 0;
			BookInfo book = mScene.CurrentBook;
			if( (this as IReadingHandler).ReadingTellPos(ref linePos) )
			{			
				book.LastPos = linePos;
			}
			mScene.Data.CurrentBook = book;
			
			book.FileName = null;
			mScene.CurrentBook = book;
			mScene.Data.CloseFile();
		}
		//continue reading
		bool IReadingHandler.ReadingContinue(UISwitch effect)
		{
			if( mScene.CurrentBook.FileName != null
			   /*&& ( mPages[0].Text != "" || mPages[1].Text != "" || mPages[2].Text != "" )*/)
			{
				mScene.ShowUI(UIType.READING,effect);
				return true;
			}
			else
				return false;

		}
		//open & reading help file
		bool mReadingHelp = false;
		void IReadingHandler.ReadingHelp()
		{
			String file = "__help__." + mScene.View.Owner.GetSystemLanguage() + ".txt";
			(this as IReadingHandler).ReadingClose();
			BookInfo book = mScene.CurrentBook;
			if( mScene.Data.OpenHelp(file,out book) )
			{
				for(int i = 0; i < PAGE_COUNT; ++i)
				{
					if( i == 0 )
						mPageInfo[0].Start = book.LastPos;
					else
						mPageInfo[i].Start = mPageInfo[i-1].Start + mPageInfo[i-1].Size;
					
					//String text = "";
					ReadResult result = mScene.Data.ReadForwardFile(ref mPageInfo[i], ref mPages[i] );
					if( result != ReadResult.ERROR )
					{
						//mPages[i].Text = text;
						//mPages[i].Height = mScene.View.Height;
						if(result == ReadResult.OK )
							mPages[i].Height = (mPageInfo[i].LinePos.Count+0.2f)*mScene.View.GetFontHeight();
						//mPages[i].Height = Math.Min(MAX_VIEW_HEIGHT, mPages[i].TextHeight );						
					}
				}//for
				
				book.FileName = null;
				mScene.CurrentBook = book;
				UpdateReadPageLayout();
				UISpTextContent.PanelY = 0;
				mScene.ShowUI(UIType.READING);
				
				mReadingHelp = true;
			}
			else
			{
				String info = String.Format( mScene.Language.MsgFileNotFound, file);
				mScene.ShowMessageBox( mScene.Language.TitleError, info);
				book.FileName = null;
				mScene.CurrentBook = book;
			}			
		}
		//goto bookpos
		bool IReadingHandler.ReadingBookPos(int pos)
		{
			if( mScene.CurrentBook.FileName == null )
				return false;
			this.UpdateLayout(mScene.Layout);
			
			BookInfo book = mScene.CurrentBook;
			book.LastPos = pos;
			mScene.CurrentBook = book;
			
			for(int i = 0; i < PAGE_COUNT; ++i)
			{
				mPageIndex[i] = i;
				
				if( i == 0 )
					mPageInfo[0].Start = book.LastPos;
				else
					mPageInfo[i].Start = mPageInfo[i-1].Start + mPageInfo[i-1].Size;
				
				//String text = "";
				ReadResult result = mScene.Data.ReadForwardFile(ref mPageInfo[i], ref mPages[i] );
				if( result != ReadResult.ERROR )
				{
					//mPages[i].Text = text;
					//mPages[i].Height = mScene.View.Height;
					if(result == ReadResult.OK )
						mPages[i].Height = (mPageInfo[i].LinePos.Count+0.2f)*mScene.View.GetFontHeight();
					//mPages[i].Height = Math.Min(MAX_VIEW_HEIGHT, mPages[i].TextHeight );						
				}
			}
			
			UpdateReadPageLayout();
			UISpTextContent.PanelY = 0;
			mScene.ShowUI(UIType.READING);
			return true;
		}
		//get current reading pos
		bool IReadingHandler.ReadingTellPos(ref int pos)
		{
			if( mScene.CurrentBook.FileName != null )
			{
				int PageID = mPageIndex[0];
				if( UISpTextContent.PanelY <= -(mPages[0].Height + mPages[1].Height) )
				{
					//mCurrentBook.LastPos = mPageInfo[2].Start;
					PageID = mPageIndex[2];
				}
				else if( UISpTextContent.PanelY <= -mPages[0].Height )
				{
					//mCurrentBook.LastPos = mPageInfo[1].Start;
					PageID = mPageIndex[1];
				}
				//else
					//mCurrentBook.LastPos = mPageInfo[0].Start;
				
				float offset = UISpTextContent.ConvertLocalToScreen( mPages[PageID].X, mPages[PageID].Y + UISpTextContent.PanelY).Y;
				
				int invisibleLines = (int)( offset/ (float)mScene.View.GetFontHeight() );
				if( invisibleLines >= 0 ) //?impossible?
					invisibleLines = 0;
				else
					invisibleLines = -invisibleLines;
				
				if( mPageInfo[PageID].LinePos != null )
					pos = mPageInfo[PageID].LinePos[invisibleLines];
				else
					pos = 0;	//no content
				
				return true;
			}
			else
			{
				pos = 0;
				return false;
			}
		}
		#endregion

		#region ReaderUI overrides
		public override void Initialize(ReaderScene scene)
		{
			base.Initialize(scene);
			#region create
            mRoot = new Panel();
            mRoot.Name = "ReadingRoot";
			mRoot.BackgroundColor = mScene.ListBackgroundColor;
			//mRoot.BackgroundStyle = DialogBackgroundStyle.Custom;
			//mRoot.CustomBackgroundColor = mScene.ListBackgroundColor;
			{
            	UISpTextContent = new ScrollPanel();
            	UISpTextContent.Name = "UISpTextContent";
				
		        // UISpTextContent
		        UISpTextContent.HorizontalScroll = false;
		        UISpTextContent.VerticalScroll = true;
		        UISpTextContent.ScrollBarVisibility = ScrollBarVisibility.Invisible;
				UISpTextContent.Visible = true;
				this.mRoot.AddChildLast(UISpTextContent);
			}
			
			//reading panel text label (text content)
			mPages = new Label[PAGE_COUNT];
			for(int i = 0; i < PAGE_COUNT; ++i )
			{
				mPages[i] = new Label();
				mPages[i].SetPosition(0,i*mScene.View.Height);
				mPages[i].SetSize(mScene.View.Width,mScene.View.Height);
				mPages[i].BackgroundColor = mScene.Reader.TextBackground;
				mPages[i].TextColor = mScene.Reader.TextColor;
				mPages[i].Font = mScene.TextFont;
				mPages[i].LineBreak = LineBreak.Character;
				mPages[i].TextTrimming = TextTrimming.None;
				mPages[i].Anchors = Anchors.Top | Anchors.Height | Anchors.Left | Anchors.Width;
				mPages[i].VerticalAlignment = VerticalAlignment.Top;
				mPages[i].HorizontalAlignment = HorizontalAlignment.Left;
				mPages[i].Visible = true;
				mPages[i].Focusable = false;
				UISpTextContent.AddChildLast(mPages[i]);
			}
			#endregion
			
			//debug 
			//mPages[0].BackgroundColor = new UIColor(1.0f, 0.0f, 0.0f, 0.55f);
			//mPages[1].BackgroundColor = new UIColor(0.0f, 1.0f, 0.0f, 0.55f);
			//mPages[2].BackgroundColor = new UIColor(0.0f, 0.0f, 1.0f, 0.55f);
			
			#region init
			//drage event
			DragGestureDetector drag = new DragGestureDetector();
			drag.MaxDistance = 10;
			drag.DragDetected += HandleReadingDrag;
			UISpTextContent.AddGestureDetector(drag);
			
			mRoot.KeyEventReceived += HandleReadingKey;
			mRoot.Focusable = false;
			UISpTextContent.Focusable = false;
			UISpTextContent.FocusStyle = FocusStyle.None;
			UISpTextContent.PanelWidth = mScene.View.Width;
			UISpTextContent.Visible = true;
			//mRoot
			//UISpTextContent.KeyEventReceived += HandleReadingKey;
			//UISpTextContent.LocalKeyReceiverWidget = UISpTextContent;
			
			mPageIndex = new int[PAGE_COUNT]{0,1,2};
			mPageInfo = new PagePos[PAGE_COUNT];
			for(int i = 0; i < PAGE_COUNT;++i)
			{
				mPageInfo[i].Start = 0;
				mPageInfo[i].Size = 0;
				mPageInfo[i].LinePos = null;
			}
			#endregion
		}
		
		public override void UpdateLayout(LayoutOrientation orientation)
		{
			switch (orientation)
            {
            case LayoutOrientation.Vertical:
				break;
			default:
				//content
                mRoot.SetPosition(0, 0);
                mRoot.SetSize(mScene.View.Width, mScene.View.Height);
                mRoot.Anchors = Anchors.Top | Anchors.Height | Anchors.Left | Anchors.Width;
				{
		            UISpTextContent.SetPosition(0, 0);
		            UISpTextContent.SetSize(mScene.View.Width, mScene.View.Height);
					//UISpTextContent.PanelHeight = mScene.View.Height*PAGE_COUNT;
		            UISpTextContent.Anchors = Anchors.Top | Anchors.Height | Anchors.Left | Anchors.Width;
		            
				}
				break;
			}
		}
		#endregion
			
		private void HandleReadingDrag(object sender,  DragEventArgs e)
		{
			if( this.Showing || this.Hiding )
				return;

			DragType drag = mScene.Control.DetectDrag(e.Distance.X,e.Distance.Y);
			if( drag == DragType.RIGHT )
				mScene.ShowUI(UIType.MAINMENU,UISwitch.LEFT);
			else if( drag == DragType.LEFT && !mScene.IsReadingHelp() && !mReadingHelp)
				mScene.ShowUI(UIType.BOOKMARKS,UISwitch.RIGHT);
			
			//const float Minimal = 200;
			//if( e.Distance.Y < -Minimal )
			else if( e.Distance.Y < 0.0f )
			{
				//check if the panel is scrolling to the end
				//if( UISpTextContent.PanelY - mScene.View.Height <= -UISpTextContent.PanelHeight )
				ReadForwardPage();
			}
			//else if( e.Distance.Y <= -Minimal )
			else if( e.Distance.Y > 0.0f )
			{
				ReadBackWardPage();
			}
		}
		
		private void UpdateReadPageLayout()
		{
			float totalHeight = 0;
			for(int i = 0; i < PAGE_COUNT; ++i )
			{
				int index = mPageIndex[i];
				
				totalHeight += mPages[index].Height;
				
				if( i > 0 )
				{
					int last = mPageIndex[i-1];
					mPages[ index ].Y = mPages[ last ].Y + mPages[ last].Height;
				}
				else
					mPages[ index ].Y = 0;
			}
			UISpTextContent.PanelHeight = totalHeight;//Math.Max(totalHeight, mScene.View.Height*(PAGE_COUNT+1));
		}
		
		private	void ReadForwardPage()
		{
			if( !mRoot.Visible )
				return;
			
			//if( !(UISpTextContent.PanelY  <= -(mScene.View.Height)*(PAGE_COUNT-1) ) )
			if( !(UISpTextContent.PanelY <= -UISpTextContent.PanelHeight+mScene.View.Height) )
				return;
			//load next text data
			//note that each page's height is large or equal than screen height
			//so when scrolled to the end,
			//there is only the last page being shown
			float hiddenHeight = mPages[ mPageIndex[ 0 ] ].Height;
			
			//String text = "";
			int backup = mPageInfo[ mPageIndex[0] ].Start;
			mPageInfo[ mPageIndex[0] ].Start = mPageInfo[ mPageIndex[2] ].Start + mPageInfo[ mPageIndex[2] ].Size;
			ReadResult result = mScene.Data.ReadForwardFile(ref mPageInfo[ mPageIndex[0] ] , ref mPages[ mPageIndex[0] ] );
			if( result != ReadResult.ERROR )
			{
				//if( mPages[ mPageIndex[0] ].Text != "" )
				if( result != ReadResult.EOF )
				{
					//feed text to the first one(scrolled up and invisible one)
					//and posititon it to the last
					//mPages[ mPageIndex[0] ].Text = text;
					//mPages[ mPageIndex[0] ].Height = Math.Min(MAX_VIEW_HEIGHT, mPages[ mPageIndex[0] ].TextHeight );
					mPages[ mPageIndex[0] ].Height = (mPageInfo[ mPageIndex[0] ].LinePos.Count+0.2f)*mScene.View.GetFontHeight();
					
					int middle = mPageIndex[1];
					mPageIndex[1] = mPageIndex[2];
					mPageIndex[2] = mPageIndex[0];
					mPageIndex[0] = middle;
					
					//re-arrange the labels
					UpdateReadPageLayout();
					//scroll
					//System.Console.WriteLine("{0},{1}", UISpTextContent.PanelY, -(mScene.View.Height)*(PAGE_COUNT-1) );
					UISpTextContent.PanelY += hiddenHeight;
					//System.Console.WriteLine("{0},{1}", UISpTextContent.PanelY, -(mScene.View.Height)*(PAGE_COUNT-1) );
					//System.Console.WriteLine("******");
				}
				else
					mPageInfo[ mPageIndex[0] ].Start = backup;
			}
				
		}
		
		private void ReadBackWardPage()
		{
			if( !mRoot.Visible )
				return;
			
			if( !(UISpTextContent.PanelY >= 0) )
				return;
			
			//load previous text data
			//String text = "";
			
			int backup = mPageInfo[ mPageIndex[2] ].Start;
			mPageInfo[ mPageIndex[2] ].Start = mPageInfo[ mPageIndex[0] ].Start - 1;
			
			ReadResult result = mScene.Data.ReadBackwardFile(ref mPageInfo[ mPageIndex[2] ], ref  mPages[ mPageIndex[2] ]);
			if( result != ReadResult.ERROR )
			{
				//if( mPages[ mPageIndex[2] ].Text != "" )
				if(result != ReadResult.EOF )
				{
					//feed text to the first one(scrolled up and invisible one)
					//and posititon it to the last
					//mPages[ mPageIndex[2] ].Text = text;
					//mPages[ mPageIndex[2] ].Height = Math.Min(MAX_VIEW_HEIGHT, mPages[ mPageIndex[2] ].TextHeight);
					mPages[ mPageIndex[2] ].Height = (mPageInfo[ mPageIndex[2] ].LinePos.Count+0.2f)*mScene.View.GetFontHeight();
					
					int middle = mPageIndex[1];
					mPageIndex[1] = mPageIndex[0];
					mPageIndex[0] = mPageIndex[2];
					mPageIndex[2] = middle;
					
					//re-arrange the labels
					UpdateReadPageLayout();
					//scroll
					float hiddenHeight = mPages[ mPageIndex[0] ].Height;
					UISpTextContent.PanelY -= hiddenHeight;
				}
				else
					mPageInfo[ mPageIndex[2] ].Start = backup;
			}
			
		}
		
		private void HandleReadingKey(object sender, KeyEventArgs e)
		{
			if( this.Showing || this.Hiding )
				return;

			if( !UISpTextContent.Visible )
				return;

			if( e.KeyEventType == KeyEventType.Up )
			{
				switch(e.KeyType)
				{
				/*
				case KeyType.Triangle:
					UISpTextContent.PanelY += (mView as PSView).GlobalFont.Middle.GetFont().Metrics.Height;
					ReadBackWardPage();
					break;
				case KeyType.Back:
					UISpTextContent.PanelY -= (mView as PSView).GlobalFont.Middle.GetFont().Metrics.Height;
					ReadForwardPage();
					break;
				*/
				case KeyType.Square:
					//page up
					float offsetUp = mScene.View.Height - mScene.View.GetFontHeight();	//reserv one line
					if( offsetUp + UISpTextContent.PanelY > 0 )
					{
						offsetUp += UISpTextContent.PanelY;
						UISpTextContent.PanelY = 0;
						ReadBackWardPage();
						UISpTextContent.PanelY += offsetUp;
						ReadBackWardPage();
					}
					else
					{
						UISpTextContent.PanelY += offsetUp;
						ReadBackWardPage();
					}
					//we need check twice, because the page movement is too large
					//ReadBackWardPage();
					break;
				case KeyType.Enter:
					//page down
					//UISpTextContent.PanelY -= mScene.View.Height - (mView as PSView).GlobalFont.Middle.GetFont().Metrics.Height;
					//ReadForwardPage();
					float offsetDown = mScene.View.Height - mScene.View.GetFontHeight();	//reserv one line
					if( UISpTextContent.PanelY - offsetDown  < -UISpTextContent.PanelHeight+mScene.View.Height )
					{
						float delta = UISpTextContent.PanelY - (-UISpTextContent.PanelHeight+mScene.View.Height);
						offsetDown -= delta;
						UISpTextContent.PanelY = -UISpTextContent.PanelHeight+mScene.View.Height;
						ReadForwardPage();
						UISpTextContent.PanelY -= offsetDown;
						ReadForwardPage();
					}
					else
					{
						UISpTextContent.PanelY -= offsetDown;
						ReadForwardPage();
					}
					break;
				case KeyType.R:
					mScene.ShowUI(UIType.MAINMENU,UISwitch.LEFT);
					break;
				case KeyType.L:
					if( !mScene.IsReadingHelp() && !mReadingHelp)
						mScene.ShowUI(UIType.BOOKMARKS,UISwitch.RIGHT);
					break;
				case KeyType.Up:
					//change font size
					int pos = 0;
					if( mScene.Reader.FontSize < MAX_FONT_SIZE &&
					   (this as IReadingHandler).ReadingTellPos(ref pos) )
					{
						mScene.Reader.FontSize = mScene.Reader.FontSize+1;
						for(int i = 0; i < PAGE_COUNT; ++i)
						{
							mPages[ mPageIndex[i] ].Font = mScene.TextFont;
						}
						(this as IReadingHandler).ReadingBookPos(pos);
					}
					break;
				case KeyType.Down:
					//change font size
					int POS = 0;
					if( mScene.Reader.FontSize > MIN_FONT_SIZE &&
					   (this as IReadingHandler).ReadingTellPos(ref POS) )
					{
						mScene.Reader.FontSize = mScene.Reader.FontSize-1;
						for(int i = 0; i < PAGE_COUNT; ++i)
						{
							mPages[ mPageIndex[i] ].Font = mScene.TextFont;
						}
						(this as IReadingHandler).ReadingBookPos(POS);
					}
					break;
				}
			}
			
			if( e.KeyEventType == KeyEventType.Down || e.KeyEventType == KeyEventType.Repeat )
			{
				switch(e.KeyType)
				{
				case KeyType.Triangle:
					//smooth up
					e.EnabledEachFrameRepeat = true;
					UISpTextContent.PanelY += 5;
					ReadBackWardPage();
					return;
				case KeyType.Back:
					//smooth down
					e.EnabledEachFrameRepeat = true;
					UISpTextContent.PanelY -= 5;
					ReadForwardPage();
					return;
				case KeyType.Left:
					//background transparency
					for(int i = 0; i < PAGE_COUNT; ++i)
					{
						UIColor c = mPages[i].BackgroundColor;
						c.A -= 0.01f;
						c.A = Math.Max(c.A,0.0f);
						mPages[i].BackgroundColor = c;
					}
					//update alpha settings
					mScene.Reader.TextBackground = mPages[0].BackgroundColor;
					break;
				case KeyType.Right:
					//background transparency
					for(int i = 0; i < PAGE_COUNT; ++i)
					{
						UIColor c = mPages[i].BackgroundColor;
						c.A += 0.01f;
						c.A = Math.Min(c.A,1.0f);
						mPages[i].BackgroundColor = c;
					}
					//update alpha settings
					mScene.Reader.TextBackground = mPages[0].BackgroundColor;
					break;
				}
			}
		}
		
	}//class
}